package yawning.mew.util;

import org.apache.commons.math.random.BitsStreamGenerator;

public class IBAA extends BitsStreamGenerator {
	private final static int ALPHA = 8;
	private final static int SIZE = (1 << ALPHA);

	private int m[];
	private int r[];
	private int r_sz;
	private int aa;
	private int bb;

	public IBAA(int seed) {
		m = new int[SIZE];
		r = new int[SIZE];
		r_sz = 0;

		setSeed(seed);
	}

	/*
	 * Straight forward port of Robert Jenkin Jr.'s reference IBAA implementation.
	 * Original: http://burtleburtle.net/bob/rand/isaac.html
	 */
	private final void ibaa() {
		int a, b, x, y;

		a = aa; b = bb;
		for (int i = 0; i < SIZE; i++) {
			x = m[i];
			a = ((a) << 19) ^ ((a) >>> 13) + m[(i + (SIZE / 2)) & (SIZE - 1)];
			m[i] = y = m[((x) & (SIZE - 1))] + a + b;
			r[i] = b = m[((y >>> ALPHA) & (SIZE - 1))] + x;
		}
		bb = b; aa = a;
	}

	@Override
	protected final int next(int nrBits) {
		if (r_sz-- == 0) {
			ibaa();
			r_sz = SIZE - 1;
		}

		return r[r_sz] >>> (32 - nrBits);
	}

	@Override
	public void setSeed(int seed) {
		long rng = seed;

		// Crappy PRNG cribbed from the commons-math MT seed routine.
		for (int i = 0; i < SIZE; i++) {
			rng = (1812433253l * (rng ^ (rng >> 30)) + i) & 0xffffffffL;
			m[i] = (int) rng;
		}
	}

	@Override
	public void setSeed(int[] seed) {
		for (int i = 0; i < seed.length; i++)
			m[i] = seed[i];
	}

	@Override
	public void setSeed(long seed) {
		setSeed((int) seed);
	}
}
